package com.apes.framework.plugin.condition.model;

import com.apes.framework.jpa.ApesBean;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.condition.PricingProcedureContext;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.CacheUtil;
import com.apes.framework.util.MapUtil;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
import org.springframework.util.StringUtils;

import javax.persistence.*;

/**
 * 功能：定价过程步骤
 *
 * @author xul
 * @create 2018-11-06 17:24
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = PricingProcedureItem.CONST_TABLE_NAME)
public class PricingProcedureItem implements ApesBean {
    public static final String CONST_TABLE_NAME = "tech_pricing_procedure_item";

    @Id
    @Column(name = "id", length = 32)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "定价过程步骤")
    @Comment("编号")
    private String id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "pricing_procedure_id", referencedColumnName = "id", nullable = false)
    @Comment("定价过程")
    private PricingProcedure pricingProcedure;

    @Column(name = "step", nullable = false)
    @Comment("步骤")
    private int step; //定价过程中的顺序

//    @Column(name = "counter", nullable = false)
//    @Comment("计数")
//    private int counter; //对步骤的进一步细化

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "condition_types_id", referencedColumnName = "id")
    @Comment("条件类型")
    private ConditionTypes conditionTypes; //定价活动中的定价因素，例如售价、折扣、运费、税费等

    @Column(name = "description", nullable = false, length = 120)
    @Comment("描述")
    private String description; //对于条件类型，系统会自动COPY过来描述。也可以在没有条件类型时手工填写。对于定价过程的每一行都可以看做定价因素

    @Column(name = "from_", nullable = false)
    @Comment("从...")
    private int from; //标示当前条件类型的条件范围

    @Column(name = "to_", nullable = false)
    @Comment("到...")
    private int to; //标示当前条件类型的条件范围

//    @Column(name = "manual", nullable = false, columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
//    @Comment("手动")
//    private boolean manual; //手工输入条件类型。勾选手动标示则代表是

    @Column(name = "mandatory", nullable = false, columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    @Comment("必需")
    private boolean mandatory; //标示条件类型在定价过程中是否是必需的

    @Column(name = "statistical", nullable = false, columnDefinition = ApesConst.FIELD_BOOLEAN_FALSE)
    @Comment("统计")
    private boolean statistical; //条件类型是否参与统计运算，勾选则代表参与

    @Column(name = "subtotal", length = 32)
    @Comment("小计")
    private String subtotal; //决定条件类型的值存到具体某个表的某个字段。

    @Column(name = "requirement", length = 32)
    @Comment("需求")
    private String requirement; //满足特定的条件需求才能够生效。是开发顾问根据特定的业务写的例程

    @Column(name = "alt_cty", length = 4000)
    @Comment("定价值公式")
    private String altCty; //替代计算类型的条件公式

    @Column(name = "alt_cbv", length = 4000)
    @Comment("基值公式")
    private String altCbv; //条件基值的替代公式

    public void process(final PricingProcedureContext context) {
        context.setPricingProcedureItem(this);
        if (!StringUtils.isEmpty(altCty)) {
            try {
                CacheUtil.getEngine().execute(altCty, MapUtil.mapper("ctx", context));
                return;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(String.format("表达式：[ %s ] 执行异常！ %s", altCty, e.getMessage()));
            }
        }
        if (conditionTypes != null) {
            boolean exist = conditionTypes.process(context);
            if (mandatory && !exist) {
                throw new RuntimeException(String.format("%s 没有定义！", conditionTypes.getName()));
            }
            context.set(conditionTypes.getId(), MapUtil.mapper("price", context.getPrice(), "value", context.getPricingValue()));
            context.set("value", context.getPricingValue());
        } else {
        }

    }
}
